package com.glodon.paas.account.security.openid.service;

import org.openid4java.message.DirectError;
import org.openid4java.message.Message;
import org.openid4java.message.ParameterList;
import org.openid4java.server.ServerManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer;

/**
 * Http Service endpoint for OpenId based authentication
 *
 * @author Don Li
 */
public class OpenIdService extends HttpServlet {
    public static final String OPENID_REQUEST_PARAM = "openid.request.param";

    private ServerManager manager;

    private static Logger LOGGER = LoggerFactory.getLogger(OpenIdService.class);

    @Override
    public void init() throws ServletException {
        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        manager = (ServerManager) context.getBean("serverManager");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        processRequest(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        processRequest(req, resp);
    }

    /**
     * Process OpenId related request sent from relaying party
     *
     * @param req  Request
     * @param resp Response
     * @throws IOException
     */
    private void processRequest(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        String mode = req.getParameter("openid.mode");
        ParameterList requestParams = new ParameterList(req.getParameterMap());
        Message responseMessage;
        String responseText = null;

        if ("associate".equals(mode)) {
            responseMessage = manager.associationResponse(requestParams);
            responseText = responseMessage.keyValueFormEncoding();
        } else if ("checkid_setup".equals(mode) || "checkid_immediate".equals(mode)) {
            // determine the service asking for the login service, default is account itself.
            String service = req.getParameter("service");
            if (service == null || "".equals(service)) {
                service = "account";
            }
            LOGGER.debug("Processing openid mode[{}] request from: {}", mode, service);

            req.getSession().setAttribute(OPENID_REQUEST_PARAM, requestParams);

            // TODO use form redirect to instead of url redirect
            resp.sendRedirect(req.getContextPath() + "/login?" + req.getQueryString());
            return;
//            getServletContext().getRequestDispatcher("/login?service=" + service).forward(req, resp);


//            // interact with the user and obtain data needed to continue
//            List userData = userInteraction(service, requestParams, resp);
//            String userSelectedId = (String) userData.get(0);
//            String userSelectedClaimedId = (String) userData.get(1);
//            Boolean authenticatedAndApproved = (Boolean) userData.get(2);
//            // process an auth request
//            responseMessage = manager.authResponse(requestParams, userSelectedId, userSelectedClaimedId, authenticatedAndApproved);
//            if (responseMessage instanceof DirectError) {
//                ServletOutputStream os = resp.getOutputStream();
//                os.write(responseMessage.keyValueFormEncoding().getBytes());
//                os.close();
//                return;
//            } else {
//                resp.sendRedirect(responseMessage.getDestinationUrl(true));
//                return;
//            }
        } else if ("check_authentication".equals(mode)) {
            // process a verification request
            responseMessage = manager.verify(requestParams);
            responseText = responseMessage.keyValueFormEncoding();
        } else {
            responseMessage = DirectError.createDirectError("Unknow request");
            responseText = responseMessage.keyValueFormEncoding();
        }
        LOGGER.debug("response text:\n{}", responseText);
        Writer writer = resp.getWriter();
        try {
            writer.write(responseText);
        } finally {
            writer.close();
        }
    }

}
